package com.example.app1.global;

import com.example.app1.enums.ResultEnum;
import com.example.app1.pojo.RestResp;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * 这个ResponseBodyAdvice的本意是：如果controller方法的返回值不是RestResp类型，则包装成RestResp类型
 * 把方法的返回值作为data
 * 但是如果目标方法的返回值是String类型，会抛出异常com.example.demo1112.pojo.RestResp cannot be cast to java.lang.String
 *
 * 原因是？
 * 内容协商的时候，会选择一个HttpMessageConverter，这里如果忘了，看oneNote笔记
 * 如果返回值是String，选择的就是 StringHttpMessageConverter
 *
 * 解决方案：
 * 1.对于返回值为String的做特殊处理：把返回值放到RestResp的data字段，再把RestResp转为json字符串
 * 2.将 Content-Type 设为 application/json；返回类型是String时，默认 Content-Type =text/plain
 */
@RestControllerAdvice(basePackages = "com.example.app1.web")
public class GlobalResponseBodyHandler implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return returnType.getParameterType() != RestResp.class;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        // "error handle by advice": "com.example.demo1112.pojo.RestResp cannot be cast to java.lang.String"
        RestResp<Object> resp = new RestResp<>(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMsg(), body);
        if(returnType.getParameterType() != String.class){
            return resp;
        }
        HttpHeaders headers = response.getHeaders();
        headers.setContentType(MediaType.valueOf("application/json"));

        ObjectMapper objectMapper = new ObjectMapper();
        String s;
        try {
            s = objectMapper.writeValueAsString(resp);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }

        return s;
    }
}
